﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;
 
using Tao;
using Tao.OpenGl;
using Tao.Platform.Windows;
using VCMDL.NET;
using WeifenLuo.WinFormsUI.Docking;

namespace VoltGameEditor
{
    public class mapDef
    {
		public static List<CMapData> MapData = new List<CMapData>();
        public static void InitMapData(int MapIndex, string Name)
        {
            MapData.Add(new CMapData());

            SetupMap(MapIndex, Name);
            SetupContainers(MapIndex);
            SetupTree(MapIndex);
            AddMapEvents(MapIndex);
            AddContainerEvents(MapIndex);
            AddTreeEvents(MapIndex);

            
        }

        public static void SetupMap(int MapIndex, string Name)
        {
			mapDef.MapData[MapIndex].Map.Show(Program.mainWin.dp_docs);
			mapDef.MapData[MapIndex].Map.Name = "map" + (Globals.NumDocs).ToString();
			mapDef.MapData[MapIndex].Map.Text = Name;
			mapDef.MapData[MapIndex].Map.TabText = Name;
			mapDef.MapData[MapIndex].Map.DockState = DockState.Document;
			mapDef.MapData[MapIndex].Map.DockAreas = DockAreas.Document;
            mapDef.MapData[MapIndex].Map.Dock = DockStyle.Fill;
			mapDef.MapData[MapIndex].Map.Icon = Properties.Resources.map;
			mapDef.MapData[MapIndex].Map.docIndex = Globals.NumDocs;
			mapDef.MapData[MapIndex].Map.docType = Globals.DocType.Map;
			mapDef.MapData[MapIndex].Map.Game = Globals.GameMode;

            for (int i = 0; i < 4; i++) //later, fix this so upper range of i is dependant on a global setting
            {
                mapDef.MapData[MapIndex].Viewports.Add(new Viewport());
                Viewport.IntViewport(i);
            }
			for (int i = 0; i < 3; i++)
			{
				mapDef.MapData[MapIndex].SplitContainers[i] = new SplitContainer();
			}
			mapDef.MapData[MapIndex].SplitContainers[0].Parent = mapDef.MapData[MapIndex].Map;

            mapDef.MapData[MapIndex].Viewports[0].Scene.Parent = mapDef.MapData[MapIndex].SplitContainers[1].Panel1;
            mapDef.MapData[MapIndex].Viewports[1].Scene.Parent = mapDef.MapData[MapIndex].SplitContainers[1].Panel2;
            mapDef.MapData[MapIndex].Viewports[2].Scene.Parent = mapDef.MapData[MapIndex].SplitContainers[2].Panel1;
            mapDef.MapData[MapIndex].Viewports[3].Scene.Parent = mapDef.MapData[MapIndex].SplitContainers[2].Panel2;

			//add the actual viewlabel to the splitcontainers
            mapDef.MapData[MapIndex].SplitContainers[1].Panel1.Controls.Add(mapDef.MapData[MapIndex].Viewports[0].Scene.ViewLabel);
            mapDef.MapData[MapIndex].SplitContainers[2].Panel1.Controls.Add(mapDef.MapData[MapIndex].Viewports[2].Scene.ViewLabel);
            mapDef.MapData[MapIndex].SplitContainers[1].Panel2.Controls.Add(mapDef.MapData[MapIndex].Viewports[1].Scene.ViewLabel);
            mapDef.MapData[MapIndex].SplitContainers[2].Panel2.Controls.Add(mapDef.MapData[MapIndex].Viewports[3].Scene.ViewLabel);

			//apply text to each of the viewlabels
            foreach (Viewport vp in MapData[MapIndex].Viewports)
            {
                functions.ChangePerspLabel(vp.Scene);
            }
        }
        static void SetupContainers(int MapIndex)
        {
            CMapData Map = mapDef.MapData[MapIndex];
            int j = Globals.NumDocs;
            
            if (MapIndex == -1)
                MapIndex = 0;

            SplitContainer[] Containers = mapDef.MapData[MapIndex].SplitContainers;
            
            Containers[0].Name = "sc1_map" + j.ToString();
            Containers[0].Dock = DockStyle.Fill;
            Containers[0].BorderStyle = BorderStyle.Fixed3D;
            Containers[0].SplitterDistance = Containers[0].Size.Width / 2;

            Containers[1].Name = "sc2_map" + j.ToString();
            Containers[1].Parent = Containers[0].Panel1;
            Containers[1].Dock = DockStyle.Fill;
            Containers[1].BorderStyle = BorderStyle.Fixed3D;
            Containers[1].Orientation = Orientation.Horizontal;
            Containers[1].SplitterDistance = Containers[0].Size.Height / 2;

            Containers[2].Name = "sc3_map" + j.ToString();
            Containers[2].Parent = Containers[0].Panel2;
            Containers[2].Dock = DockStyle.Fill;
            Containers[2].BorderStyle = BorderStyle.Fixed3D;
            Containers[2].Orientation = Orientation.Horizontal;
            Containers[2].SplitterDistance = Containers[0].Size.Height / 2;
        }
        static void SetupTree(int MapIndex)
        {
            CMapData Map = mapDef.MapData[MapIndex];
            Map.Tree.Nodes.Clear();

            Map.Tree.Name = "treeMap" + mapDef.GetDocumentIndex() + 1;

			Map.Tree.Parent = Program.ObjPane.tc2_tpTree;
            Map.Tree.Dock = DockStyle.Fill;
            Map.Tree.HotTracking = true;
            Map.Tree.FullRowSelect = true;
            Map.Tree.ImageList = Program.mainWin.il_mapEnts;
            Map.Tree.AllowDrop = true;
            Map.Tree.HideSelection = false;
            Map.Tree.LabelEdit = true;

            Map.Tree.BringToFront();

            Map.Tree.Nodes.Add(new TreeNodeEx("worldspawn", 3, 3));
            Map.Tree.ExpandAll();
            Map.Worldspawn = new WorldSpawn();
            
        }

        static void AddMapEvents(int MapIndex)
        {
            Form MapForm = mapDef.MapData[MapIndex].Map;

            MapForm.FormClosing += new FormClosingEventHandler(mapDef.map_FormClosing);
			MapForm.DockChanged+=new EventHandler(mapDef.map_DockChanged);
        }
        static void AddContainerEvents(int MapIndex)
        {
            CMapData Map = mapDef.MapData[MapIndex];
            Map.SplitContainers[1].SplitterMoving += new SplitterCancelEventHandler(SC1_SplitterMoving);
            Map.SplitContainers[2].SplitterMoving += new SplitterCancelEventHandler(SC2_SplitterMoving);
        }
        static void AddTreeEvents(int MapIndex)
        {
            CMapData Map = mapDef.MapData[MapIndex];

            if (Map.Tree == null)
                return;
            Map.Tree.AfterSelect += new TreeViewEventHandler(mapDef.trees_AfterSelect);
            Map.Tree.BeforeLabelEdit += new NodeLabelEditEventHandler(mapDef.trees_BeforeLabelEdit);
            Map.Tree.AfterLabelEdit += new NodeLabelEditEventHandler(trees_AfterLabelEdit);
            Map.Tree.DragDrop += new DragEventHandler(mapDef.trees_DragDrop);
            Map.Tree.DragEnter += new DragEventHandler(mapDef.trees_DragEnter);
            Map.Tree.DragLeave += new EventHandler(mapDef.trees_DragLeave);
            Map.Tree.NodeMouseDoubleClick += new TreeNodeMouseClickEventHandler(mapDef.trees_NodeMouseDoubleClick);
            Map.Tree.KeyDown += new KeyEventHandler(mapDef.trees_KeyDown);

        }

		public static int GetDocumentIndex()
		{
			DockContentEx dc = ((DockContentEx)Program.mainWin.dp_docs.ActiveDocument.DockHandler.Content);
			if (dc.docType == Globals.DocType.Map)
			{
				int i = 0;
				foreach (CMapData m in MapData)
				{
					if (Program.mainWin.dp_docs.ActiveDocument.DockHandler.TabText == m.Map.TabText)
					{
						return i;
					}
					i++;
				}
			}
			else if (dc.docType == Globals.DocType.StartPage)
			{
				return -1;
			}
			
			return -2;
		}
     
        static void map_FormClosing(object sender, FormClosingEventArgs e)
        {

        }
		static void map_DockChanged(object sender, EventArgs e)
		{
			MessageBox.Show("map_DockChanged");
		}

        static void SC1_SplitterMoving(object sender, SplitterCancelEventArgs e)
        {
            mapDef.MapData[mapDef.GetDocumentIndex()].SplitContainers[2].SplitterDistance = e.SplitY;

        }
        static void SC2_SplitterMoving(object sender, SplitterCancelEventArgs e)
        {
            mapDef.MapData[mapDef.GetDocumentIndex()].SplitContainers[1].SplitterDistance = e.SplitY;
        }

        static void trees_AfterSelect(object sender, TreeViewEventArgs e)
        {

        }
        static void trees_BeforeLabelEdit(object sender, NodeLabelEditEventArgs e)
        {
            TreeNodeEx node = ((TreeNodeEx)mapDef.MapData[mapDef.GetDocumentIndex()].Tree.SelectedNode);
            if (node.Text == "worldspawn")
                e.CancelEdit = true;
            Framework.EditObject(node);
        }
        static void trees_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
        {

        }
        static void trees_DragDrop(object sender, DragEventArgs e)
        {
            int i = mapDef.GetDocumentIndex();
            mapDef.MapData[i].Tree.BackColor = Color.White;
            if (e.Data.GetDataPresent(typeof(TreeNodeEx)))
            {
                string[] str = e.Data.GetFormats();

                TreeNodeEx node = (TreeNodeEx)e.Data.GetData(str[1], true);

                node.ObjIndex = mapDef.MapData[i].Entities.Count;
                node.ImageIndex = 5;
                node.SelectedImageIndex = 5;
				
				Framework.AddEntity(new Vector3(0, 0, 0), node.Text, true, (IDictionary)node.DefaultKVPs);
                mapDef.MapData[i].Tree.Nodes[0].Nodes.Add(node);
            }

        }
        static void trees_DragEnter(object sender, DragEventArgs e)
        {
            int i = mapDef.GetDocumentIndex();
            mapDef.MapData[i].Tree.BackColor = Color.Cornsilk;
            e.Effect = DragDropEffects.Copy;
        }
        static void trees_DragLeave(object sender, EventArgs e)
        {
            int i = mapDef.GetDocumentIndex();
            mapDef.MapData[i].Tree.BackColor = Color.White;
        }
        static void trees_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                TreeView Tree = (TreeView)sender;
                int i = mapDef.GetDocumentIndex();
                int j = ((TreeNodeEx)mapDef.MapData[i].Tree.SelectedNode).ObjIndex;
				TreeNodeEx node = ((TreeNodeEx)mapDef.MapData[i].Tree.SelectedNode);

				Program.ObjPane.tabControl2.SelectedIndex = 1;

                if (mapDef.MapData[i].Tree.SelectedNode != null)
                {
                    switch (node.ItemType)
                    {
                        case MapObject.Type.Brush:
                            {
                                MapObject.SetKVP2DataGrid(mapDef.MapData[i].Brushes[j].KVPs,node);
                                break;
                            }
                        case MapObject.Type.Entity:
                            {
                                MapObject.SetKVP2DataGrid(mapDef.MapData[i].Entities[j].KVPs,node);
                                break;
                            }
                        case MapObject.Type.Group:
                            {
                                MapObject.SetKVP2DataGrid(mapDef.MapData[i].Groups[j].KVPs,node);
                                break;
                            }
                        case MapObject.Type.TwoDeeObj:
                            {
                                MapObject.SetKVP2DataGrid(mapDef.MapData[i].TwoDeeObjects[j].KVPs,node);
                                break;
                            }
                        case MapObject.Type.Worldspawn:
                            {
                                MapObject.SetKVP2DataGrid(mapDef.MapData[i].Worldspawn.KVPs,node);
                                break;
                            }
						case MapObject.Type.CustomObject:
							{
								MapObject.SetKVP2DataGrid(mapDef.MapData[i].Entities[j].KVPs,node);
								break;
							}
                    }
                }
            }
        }
        static void trees_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Delete:
                    {
                        Framework.DestroyObject(((TreeNodeEx)mapDef.MapData[mapDef.GetDocumentIndex()].Tree.SelectedNode)); //weird bug: unable to cast if its a group???
                        break;
                    }
            }
        }
    }

    public class CMapData
    {
		/// <summary>
		/// Contains all the data for each map that is created
		/// </summary>
		public DockContentEx Map = new DockContentEx();
        public TreeView Tree = new TreeView();

        public WorldSpawn Worldspawn = new WorldSpawn();
        public List<MapBrush> Brushes = new List<MapBrush>();
        public List<Entity> Entities = new List<Entity>();
        public List<MapGroup> Groups = new List<MapGroup>();
        public List<TwoDeeObj> TwoDeeObjects = new List<TwoDeeObj>();

        public SplitContainer[] SplitContainers = new SplitContainer[3];

        public List<Viewport> Viewports = new List<Viewport>();
    }
    //---

	

    public class MapObject
    {
		/// <summary>
		/// This is the common vars and methods to all other object types
		/// </summary>
        public string Name;

        public IDictionary KVPs = new Dictionary<string,string>();
        public Vector3 Origin = new Vector3();

        public enum Type
        {
            Worldspawn,
            Brush,
            Entity,
            Group,
            TwoDeeObj,
            Face,
			CustomObject
        }

        public static void SetKVP2DataGrid(IDictionary KVPs, TreeNodeEx sender)
        {
            
        }

        public static Dictionary<string,string> GetDefaultKVPs(string DictName)
        {
            Array arr = new string[] { };
            Boolean FoundEnt = false;
            Dictionary<string,string> KVPs = new Dictionary<string,string>();
            foreach (Dictionary<string, string> dict in arr)
            {
                if (FoundEnt == true)
                    break;
                //int i = 1;
                foreach (KeyValuePair<string, string> kvp in dict)
                {
                    if (kvp.Key == "classname" && kvp.Value == DictName)
                    {
                        FoundEnt = true;
                        KVPs.Add(kvp.Key, kvp.Value);
                    }
                    else if (kvp.Key == "classname" && kvp.Value != DictName)
                        break;
                    else
                    {
                        KVPs.Add(kvp.Key, kvp.Value);
                    }
                }
            }
            return (KVPs);
        }
    }

    public class Vector2
    {
        public float X, Y;

        public Vector2(float X, float Y)
        {
            this.X = X;
            this.Y = Y;
        }
        public Vector2()
        {
            Clear();
        }

        public void Clear()
        {
            X = Y = 0;
        }

        public override string ToString()
        {
            string s = X + " " + Y;
            return s;
        }
    }

    public class Face
    {
        public Vector3[] Normals = new Vector3[3];
        public List<Vector3> Points = new List<Vector3>();
		public List<Point> TexCoords = new List<Point>();
    }
	public class MapBrush : MapObject
    {
        
        public List<Face> Faces = new List<Face>();
    }
	public class Entity : MapObject
    {
        public string extModelRef; //filename of external model
    }
	public class TwoDeeObj : MapObject
    {
        public List<Vector3> Vectors = new List<Vector3>();
        public int Sides;
        public Vector2 RadiusXY = new Vector2();
        public TwoDeeObj()
        {
            
        }
    }
	public class MapGroup : MapObject
    {
        public List<TreeNodeEx> Children = new List<TreeNodeEx>();

        public MapGroup()
        {
            this.KVPs.Add("Name", "Group");
            this.KVPs.Add("Color", "0 0 0");
            this.KVPs.Add("Origin", "0 0 0");
            this.KVPs.Add("Glued", "True");
        }
    }
    public class WorldSpawn                             
    {
        public IDictionary KVPs = new Dictionary<string, string>();
        public Globals.Game Game = Globals.Game.Quake_2; //default gamemode

        public WorldSpawn()
        {
			//the following is temporary, rid of this and add a function to import it from the game file.
            this.KVPs = MapObject.GetDefaultKVPs("worldspawn");
        }
    }

    public class TreeNodeEx : TreeNode
    {
		public MapObject.Type ItemType; //to indentify the object
        public int ObjIndex; //for identifying its index in the object's list.
		public IDictionary DefaultKVPs = new Dictionary<string, string>();

        public TreeNodeEx()
        {
            
        }
        public TreeNodeEx(string text) : base(text) { }
        public TreeNodeEx(string text, int imageIndex, int selectedImageIndex) : base(text, imageIndex, selectedImageIndex) { }
        public TreeNodeEx(string text, int imageIndex, int selectedImageIndex, TreeNodeEx[] children) : base(text, imageIndex, selectedImageIndex, children) { }
    }

    public class Viewport
    {
        private static CControlMouseMoveHook port_MouseHook;

        Vector3 createVertexPos = new Vector3();

        public GlControl Scene;
        
        public enum Perspectives
        {
            Top,
            Front,
            Side,
            ThreeDScene
        }

        public static void IntViewport(int vpIndex)
        {
            int MapIndex = 0;
            if (mapDef.GetDocumentIndex() != -1)
                MapIndex = mapDef.GetDocumentIndex();

            mapDef.MapData[MapIndex].Viewports[vpIndex].Scene = new GlControl();
            mapDef.MapData[MapIndex].Viewports[vpIndex].Scene.Name = "vport" + vpIndex.ToString();
            mapDef.MapData[MapIndex].Viewports[vpIndex].Scene.Dock = DockStyle.Fill;
            mapDef.MapData[MapIndex].Viewports[vpIndex].Scene.AllowDrop = true;
            mapDef.MapData[MapIndex].Viewports[vpIndex].Scene.vpIndex = vpIndex;
            mapDef.MapData[MapIndex].Viewports[vpIndex].Scene.InitializeContexts();

            //event handler constructors
            mapDef.MapData[MapIndex].Viewports[vpIndex].Scene.Paint += new PaintEventHandler(Viewport.port_Paint);
            mapDef.MapData[MapIndex].Viewports[vpIndex].Scene.KeyDown += new KeyEventHandler(Viewport.port_KeyDown);
            mapDef.MapData[MapIndex].Viewports[vpIndex].Scene.KeyUp += new KeyEventHandler(Viewport.port_KeyUp);
            mapDef.MapData[MapIndex].Viewports[vpIndex].Scene.SizeChanged += new EventHandler(Viewport.port_SizeChanged);
            mapDef.MapData[MapIndex].Viewports[vpIndex].Scene.DragEnter += new DragEventHandler(Viewport.port_DragEnter);
            mapDef.MapData[MapIndex].Viewports[vpIndex].Scene.DragLeave += new EventHandler(Viewport.port_DragLeave);
            mapDef.MapData[MapIndex].Viewports[vpIndex].Scene.DragDrop += new DragEventHandler(Viewport.port_DragDrop);
            mapDef.MapData[MapIndex].Viewports[vpIndex].Scene.PerspectiveChanged += new PerspEventHandler(Viewport.port_PerspectiveChanged);
            mapDef.MapData[MapIndex].Viewports[vpIndex].Scene.ShadingChanged += new ShadingEventHandler(Viewport.port_ShadingChanged);
            port_MouseHook = new CControlMouseMoveHook(mapDef.MapData[MapIndex].Viewports[vpIndex].Scene, Viewport.port_MouseDown, Viewport.port_MouseUp, Viewport.port_MouseMove);

            if (vpIndex == 0)
            {
                mapDef.MapData[MapIndex].Viewports[vpIndex].Scene.is3d = true;
                mapDef.MapData[MapIndex].Viewports[vpIndex].Scene.ShadeMode = Shading.Textured;
            }
            else if (vpIndex > 0)
            {
                mapDef.MapData[MapIndex].Viewports[vpIndex].Scene.is3d = false;
                mapDef.MapData[MapIndex].Viewports[vpIndex].Scene.ShadeMode = Shading.Wireframe;
            }

            float R = AppSettings.Theming.Color_2dViewBG.R / 255f;
            float G = AppSettings.Theming.Color_2dViewBG.G / 255f;
            float B = AppSettings.Theming.Color_2dViewBG.B / 255f;
            float A = AppSettings.Theming.Color_2dViewBG.A / 255f;

            Gl.glClearColor(R, G, B, A);                                     // Background Color
            Gl.glEnable(Gl.GL_TEXTURE_2D);                                      // Enable Texture Mapping
            Gl.glShadeModel(Gl.GL_SMOOTH);                                      // Enable Smooth Shading

            Gl.glClearDepth(1);                                                 // Depth Buffer Setup
            Gl.glEnable(Gl.GL_DEPTH_TEST);                                      // Enables Depth Testing
            Gl.glDepthFunc(Gl.GL_LEQUAL);                                       // The Type Of Depth Testing To Do

            Gl.glEnable(Gl.GL_BLEND);
            Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA);

            Gl.glHint(Gl.GL_PERSPECTIVE_CORRECTION_HINT, Gl.GL_NICEST);

            //Setup the camera
            mapDef.MapData[MapIndex].Viewports[vpIndex].Scene.Cam = new NewCamera();
            Viewport.ResetCamera(mapDef.MapData[MapIndex].Viewports[vpIndex].Scene);
            //--------------

            ReshapeWindow(mapDef.MapData[MapIndex].Viewports[vpIndex].Scene);

            if (vpIndex == 0)
                mapDef.MapData[MapIndex].Viewports[0].Scene.Perspective = Perspectives.ThreeDScene;
            else if (vpIndex == 1)
                mapDef.MapData[MapIndex].Viewports[1].Scene.Perspective = Perspectives.Front;
            else if (vpIndex == 2)
                mapDef.MapData[MapIndex].Viewports[2].Scene.Perspective = Perspectives.Top;
            else if (vpIndex == 3)
                mapDef.MapData[MapIndex].Viewports[3].Scene.Perspective = Perspectives.Side;

        }

        public static double Q_CalcFovY(double fovX, double width, double height)
        {
            return (Math.Atan(height / (width / Math.Tan(fovX / 360.0 * Math.PI)))) * ((180.0 / Math.PI) * 2);
        }

        public static void ReshapeWindow(GlControl glc)
        {
            if (glc.Cam == null)
                return;
			float w = (float)glc.Width;
			float h = (float)glc.Height;
			float aspect = 1.0f * (w / h);

            Gl.glViewport(0, 0, glc.Width, glc.Height);

			if(glc.renderFog)
				glc.Cam.perspective(90, aspect, 1, AppSettings.Fog.FogDistance*4);
			else
				glc.Cam.perspective(90, aspect, 1, 99999);
        }

        public static void DrawAxis()
        {
            Gl.glLineWidth(1.5f); 
            Gl.glBegin(Gl.GL_LINES); 
            /* X */Gl.glColor3ub(255, 0, 0); 
            Gl.glVertex3i(0, 0, 0); 
            Gl.glVertex3i(64, 0, 0);
            /* Y */Gl.glColor3ub(0, 255, 0); 
            Gl.glVertex3i(0, 0, 0); 
            Gl.glVertex3i(0, 64, 0);
            /* Z */Gl.glColor3ub(0, 0, 255); 
            Gl.glVertex3i(0, 0, 0);
			Gl.glVertex3i(0, 0, 64); 
            Gl.glEnd(); 
            Gl.glLineWidth(1);
        }

        private static void ResetCamera(GlControl glc)
		{
			glc.Cam.lookAt(new Vector3(0, -256, 256), new Vector3(0, 0, 0), new Vector3(0, 0, 1));
			glc.g_PanPosition = new Vector3();
            glc.g_OldPanPosition = new Vector3();
			glc.Draw();
        }

		public static void Setup3dView(GlControl glc)
		{
			if (glc.renderLighting)
				Gl.glEnable(Gl.GL_LIGHTING);
			else
				Gl.glDisable(Gl.GL_LIGHTING);
			Gl.glViewport(0, 0, glc.Width, glc.Height);
			Gl.glMultMatrixf(glc.Cam.getProjectionMatrix().toFloatArray());
		} //keep just in case (this at the moment is not called)

		public static void Setup2DOrtho(GlControl glc, float X, float Y)
        {
			Gl.glViewport(0, 0, glc.Width, glc.Height);
			Gl.glOrtho(0, glc.Width / Globals.Zoom2DFactor, 0, glc.Height / Globals.Zoom2DFactor, 0, 99999);
			Gl.glTranslatef((glc.Width / Globals.Zoom2DFactor) / 2 + X, (glc.Height / Globals.Zoom2DFactor) / 2 + Y, -(99999 / 2));
        }

        private static void port_Paint(object sender, PaintEventArgs e) 
        {
            GlControl glc = (GlControl)sender;
            int i = mapDef.GetDocumentIndex();

            Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);	// Clear The Screen And The Depth Buffer
            Gl.glMatrixMode(Gl.GL_PROJECTION);
			Gl.glLoadIdentity();

			Gl.glMatrixMode(Gl.GL_MODELVIEW);
			Gl.glLoadIdentity();

			Gl.glEnable(Gl.GL_TEXTURE_2D);

            if (glc.is3d == true)
            {	
				Gl.glViewport(0, 0, glc.Width, glc.Height);
				Gl.glMultMatrixf(glc.Cam.getProjectionMatrix().toFloatArray());
				Gl.glMultMatrixf(glc.Cam.getViewMatrix().toFloatArray());

				if (glc.renderLighting)
					Gl.glEnable(Gl.GL_LIGHTING);
				else
					Gl.glDisable(Gl.GL_LIGHTING);
            }
            else
            {
				 Setup2DOrtho(glc, glc.g_PanPosition.y, glc.g_PanPosition.x);
            }

			switch (glc.Perspective)
			{
			    case Perspectives.ThreeDScene:
					
					break;
				case Viewport.Perspectives.Top:   //XY
					Gl.glRotatef(0, 1, 0, 0);
					break;
				case Viewport.Perspectives.Front: //XZ
					Gl.glRotatef(-90, 1, 0, 0);
					break;
				case Viewport.Perspectives.Side:  //YZ
					Gl.glRotatef(-90, 0, 1, 0);
					Gl.glRotatef(-90, 1, 0, 0);
					break;
			}

			if (glc.renderFog)
			{
				float R = 1.0f;//AppSettings.Theming.Color_Fog.R / 255f;
				float G = 0.0f;//AppSettings.Theming.Color_Fog.G / 255f;
				float B = 0.0f;//AppSettings.Theming.Color_Fog.B / 255f;
				float A = AppSettings.Theming.Color_Fog.A / 255f;

				Gl.glFogi(Gl.GL_FOG_MODE, Gl.GL_LINEAR);							// Fog Mode
				Gl.glFogfv(Gl.GL_FOG_COLOR, new float[4] { R, G, B, A });			// Set Fog Color
				Gl.glFogf(Gl.GL_FOG_DENSITY, AppSettings.Fog.FogDensity / 100);		// How Dense Will The Fog Be
				Gl.glHint(Gl.GL_FOG_HINT, Gl.GL_NICEST);							// Fog Hint Value
				Gl.glFogf(Gl.GL_FOG_START, AppSettings.Fog.FogDistance);			// Fog Start Depth
				Gl.glFogf(Gl.GL_FOG_END, AppSettings.Fog.FogDistance * 4);			// Fog End Depth
				Gl.glEnable(Gl.GL_FOG);							
			}
			else
			{
				Gl.glDisable(Gl.GL_FOG);
			}

			Gl.glColor4ub(255, 255, 255, 255);
            Gl.glBegin(Gl.GL_QUADS);
            foreach (MapBrush brush in mapDef.MapData[i].Brushes)
            {
				Gl.glColor3ub(AppSettings.Theming.Color_ObjectLines.R, AppSettings.Theming.Color_ObjectLines.G, AppSettings.Theming.Color_ObjectLines.B);
				foreach (Face face in brush.Faces)
				{
					//if (glc.ShadeMode == Shading.Textured)
						//Gl.glBindTexture(Gl.GL_TEXTURE_2D, face.Texture.GetGLID());

					for (int x = 0; x < face.Points.Count; ++x)
					{
						Gl.glTexCoord2f(face.TexCoords[x].X, face.TexCoords[x].Y);
						Gl.glVertex3f(face.Points[x].x, face.Points[x].y, face.Points[x].z);
					}

					Gl.glBindTexture(Gl.GL_TEXTURE_2D, 0);
				}
            }
			Gl.glEnd();
            foreach (Entity ent in mapDef.MapData[i].Entities)
            {
                //TODO :: Draw all the models, each stored in ent.ExtModelRef
            }
			
			if (glc.showGrid == true)
				functions.DrawGrid(AppSettings.General.GridSize, 8192, ((GlControl)sender).Perspective);
			DrawAxis();
        }
        private static void port_MouseUp(object sender, HookMouseEventArgs e)
        {
            GlControl glc = (GlControl)sender;

			if (Globals.isCenterOrbit) //Reset the view back to normal
			{
				Vector3 vec3E = glc.Cam.getEye();
				Vector3 vec3T = glc.Cam.getTarget();
				glc.Cam.setBehavior(NewCamera.CameraBehavior.CAMERA_BEHAVIOR_SPECTATOR);
				glc.Cam.lookAt(vec3E, vec3T, new Vector3(0, 0, 1));
			}
			
			Globals.isZooming = Globals.isPanning = Globals.isOrbit = Globals.isCenterOrbit = false;

			if (glc.PointToClient(e.ClickPos) == e.MouseEvent.Location && e.MouseEvent.Button == System.Windows.Forms.MouseButtons.Right)
            {
                if (glc.is3d == false)
                    Program.mainWin.m_vport_togLighting.Visible = false;
                else
                {
                    Program.mainWin.m_vport_togLighting.Visible = true;
					if (glc.renderLighting)
						Program.mainWin.m_vport_togLighting.Checked = true;
					else
						Program.mainWin.m_vport_togLighting.Checked = false;
                }
                if (glc.showGrid)
					Program.mainWin.m_vport_togGrid.Checked = true;
                else
					Program.mainWin.m_vport_togGrid.Checked = false;
                Program.mainWin.cm_vport.Show(glc, e.MouseEvent.Location);
                Program.mainWin.glctrl = glc;
                return;
            }
			functions.InvalidateViewports();
        }
        private static void port_MouseDown(object sender, HookMouseEventArgs e)
        {
            GlControl glc = (GlControl)sender;
			if (e.MouseEvent.Button == MouseButtons.Right && glc.is3d == true)
			{
				if (Control.ModifierKeys == Keys.Shift)
				{
					Globals.isCenterOrbit = true;
					Vector3 vec3E = glc.Cam.getEye();
					Vector3 vec3T = glc.SelectedObj.Origin;
					glc.Cam.setBehavior(NewCamera.CameraBehavior.CAMERA_BEHAVIOR_ORBIT);
					glc.Cam.lookAt(vec3E, vec3T, new Vector3(0, 0, 1));
				}
				else
					Globals.isOrbit = true;
			}
			else if (e.MouseEvent.Button == MouseButtons.Right && glc.is3d == false)
				Globals.isPanning = true;
			else if (e.MouseEvent.Button == MouseButtons.Middle)
				Globals.isZooming = true;
			else if (e.MouseEvent.Button == MouseButtons.Left)
			{
				//perform frustrum ops here
			}
        }
        private static void port_MouseMove(object sender, HookMouseEventArgs e)
        {
            int MapIndex = mapDef.GetDocumentIndex();
            GlControl glc = ((GlControl)sender);
            Vector3 forward = new Vector3(), right = new Vector3(), up = new Vector3();
            glc.Cam.getViewDirection().ToAngles().ToVectors(ref forward, ref right, ref up);

			if (Globals.isOrbit || Globals.isCenterOrbit)
			{
				glc.Cam.rotate(-e.MoveDelta.X, -e.MoveDelta.Y,0);
				
				mapDef.MapData[MapIndex].Viewports[glc.vpIndex].Scene.ContextMenuStrip = null;
			}
			else if (Globals.isPanning)
			{
				glc.g_PanPosition += new Vector3((e.MoveDelta.Y * Globals.moveSpeed) / Globals.Zoom2DFactor, (-e.MoveDelta.X * Globals.moveSpeed) / Globals.Zoom2DFactor, 0);
			}
			else if (Globals.isZooming)
			{
				if (glc.is3d == true)
				{
					Vector3 vec3 = glc.Cam.getPosition();
					glc.Cam.setPosition(vec3 + ((e.MoveDelta.Y < 0) ? forward * Globals.Zoom3DFactor : -(forward * Globals.Zoom3DFactor)));
				}
				else
				{
					Globals.Zoom2DFactor -= ((float)e.MoveDelta.Y / 100) * Globals.Zoom2DFactor;
					if (Globals.Zoom2DFactor >= 20)
						Globals.Zoom2DFactor = 20;
				}
			}
                        
            //Update the Choords label here if 2d ortho view
            if (glc.Perspective != Perspectives.ThreeDScene)
            {
				//new Vector3(CMDLGlobals.g_PanPosition.x, (float)CMDLGlobals.g_PanPosition.y + ((float)e.MoveDelta.X / CMDLGlobals.g_Zoom2DFactor), (float)CMDLGlobals.g_PanPosition.z + -((float)e.MoveDelta.Y / CMDLGlobals.g_Zoom2DFactor)));
				glc.g_2dMouseVec = new Vector2(e.MouseEvent.X - glc.g_PanPosition.y, e.MouseEvent.Y + glc.g_PanPosition.x);
                Program.mainWin.lbl_coords.Text = "X=" + glc.g_2dMouseVec.X + " , " + " Y=" + glc.g_2dMouseVec.Y;
            }

			if(Globals.isPanning || Globals.isOrbit||Globals.isZooming || Globals.isCenterOrbit)
				glc.Draw();
        }
        private static void port_KeyDown(object sender, KeyEventArgs e)
        {
            int i = mapDef.GetDocumentIndex();
            GlControl glc = ((GlControl)sender);
            Vector3 vec3 = glc.Cam.getPosition(); //Direction
            Vector3 forward = new Vector3(), right = new Vector3(), up = new Vector3();
            glc.Cam.getViewDirection().ToAngles().ToVectors(ref forward, ref right, ref up);

            if (e.Shift == true)
            { ;}

            if (e.KeyCode == Keys.W) //move forward
            {
                
                if (glc.vpIndex == 0 ) //3d view
                    glc.Cam.setPosition(vec3 + forward * Globals.SpeedMultiplier);
                else
                {
                    
                }

            }
            if (e.KeyCode == Keys.S) //move backward
            {

                if (glc.vpIndex == 0) //3d view
                    glc.Cam.setPosition(vec3 - forward * Globals.SpeedMultiplier);
                else
                {

                }

            }
            if (e.KeyCode == Keys.A) //move left
            {

                if (glc.vpIndex == 0) //3d view
                    glc.Cam.rotate(Globals.SpeedMultiplier, 0, 0);
                else
                {

                }

            }
            if (e.KeyCode == Keys.D) //move right
            {

                if (glc.vpIndex == 0) //3d view
                    glc.Cam.rotate(-Globals.SpeedMultiplier, 0, 0);
                else
                {

                }

            }
            glc.Draw();
        }
        private static void port_KeyUp(object sender, KeyEventArgs e)
        {
            
        }
        private static void port_SizeChanged(object sender, EventArgs e)
        {
            int MapIndex = mapDef.GetDocumentIndex();
            ReshapeWindow((GlControl)sender);
        }
        private static void port_PerspectiveChanged(GlControl glc, EventArgs e)
        {
            int i = glc.vpIndex;
            int MapIndex = mapDef.GetDocumentIndex();
            switch (glc.Perspective)
            {
                case Perspectives.ThreeDScene:
                    {
                        mapDef.MapData[MapIndex].Viewports[i].Scene.Cam.setBehavior(NewCamera.CameraBehavior.CAMERA_BEHAVIOR_FIRST_PERSON);
						glc.is3d = true;
                        break;
                    }
                case Viewport.Perspectives.Top:
                    {
                        mapDef.MapData[MapIndex].Viewports[i].Scene.Cam.setBehavior(NewCamera.CameraBehavior.CAMERA_BEHAVIOR_ORBIT);
						glc.is3d = false;
                        break;
                    }
                case Viewport.Perspectives.Front:
                    {
                        mapDef.MapData[MapIndex].Viewports[i].Scene.Cam.setBehavior(NewCamera.CameraBehavior.CAMERA_BEHAVIOR_ORBIT);
						glc.is3d = false;
                        break;
                    }
                case Viewport.Perspectives.Side:
                    {
                        mapDef.MapData[MapIndex].Viewports[i].Scene.Cam.setBehavior(NewCamera.CameraBehavior.CAMERA_BEHAVIOR_ORBIT);
						glc.is3d = false;
                        break;
                    }
            }
			ResetCamera(glc);
            glc.Draw();
			functions.ChangePerspLabel(glc);
        }
        private static void port_ShadingChanged(Shading Type, GlControl glc, EventArgs e)
		{
			switch (Type)
			{
				case Shading.Solid:
					Gl.glDisable(Gl.GL_TEXTURE_2D);
					Gl.glPolygonMode(Gl.GL_BACK, Gl.GL_FILL);
					break;
				case Shading.Textured:
					Gl.glPolygonMode(Gl.GL_FRONT, Gl.GL_FILL);
					Gl.glEnable(Gl.GL_TEXTURE_2D);
					break;
				case Shading.Wireframe:
					Gl.glDisable(Gl.GL_TEXTURE_2D);
					Gl.glPolygonMode(Gl.GL_FRONT_AND_BACK, Gl.GL_LINE);
					break;
			}
			glc.Draw();
		}
        private static void port_DragEnter(object Sender, DragEventArgs e)
		{
			((GlControl)Sender).BorderStyle = BorderStyle.Fixed3D;
			e.Effect = DragDropEffects.Copy;
		}
        private static void port_DragLeave(object Sender, EventArgs e)
		{
			((GlControl)Sender).BorderStyle = BorderStyle.None;
		}
        private static void port_DragDrop(object Sender, DragEventArgs e)
		{
			GlControl glc = (GlControl)Sender;
			Vector3 vec3 = new Vector3(glc.g_PanPosition.x, glc.g_PanPosition.y, glc.g_PanPosition.z);
			if (e.Data.GetDataPresent(typeof(TreeNodeEx)))
			{
				string[] str = e.Data.GetFormats();
				int i = mapDef.GetDocumentIndex();

				TreeNodeEx node = (TreeNodeEx)e.Data.GetData(str[1], true);

				node.ObjIndex = mapDef.MapData[i].Entities.Count;
				node.ImageIndex = 5;
				node.SelectedImageIndex = 5;

				Framework.AddEntity(vec3, node.Text, true, (IDictionary)node.DefaultKVPs);
				mapDef.MapData[i].Tree.Nodes[0].Nodes.Add(node);

				//TODO:: Import the model "models/Entity.Obj" and assign it to the object
			}
		}
    }
     
    public class HookMouseEventArgs
    {
        public Point MoveDelta, OldPosition, ClickPos;
        public MouseEventArgs MouseEvent;

        public HookMouseEventArgs(MouseEventArgs e)
        {
            MouseEvent = e;
        }

        public HookMouseEventArgs(MouseEventArgs e, Point MoveDelta, Point OldPosition, Point ClickPosition)
        {
            this.MouseEvent = e;
            this.MoveDelta = MoveDelta;
            this.OldPosition = OldPosition;
            this.ClickPos = ClickPosition;
        }
    }

    delegate void MouseHookEventHandler(Object sender, HookMouseEventArgs e);
    class CControlMouseMoveHook
    {
        private Control linkedCtrl;
        private Point oldPos, clickPos;
        private MouseHookEventHandler MouseDown, MouseUp, MouseMove;

        public CControlMouseMoveHook(Control _linkedCtrl, MouseHookEventHandler _MouseDown, MouseHookEventHandler _MouseUp, MouseHookEventHandler _MouseMove)
        {
            linkedCtrl = _linkedCtrl;

            linkedCtrl.MouseDown += MouseDownHandler;
            linkedCtrl.MouseUp += MouseUpHandler;
            linkedCtrl.MouseMove += MouseMoveHandler;

            MouseDown = _MouseDown;
            MouseUp = _MouseUp;
            MouseMove = _MouseMove;
        }

        void MouseDownHandler(Object sender, MouseEventArgs e)
        {
            oldPos = Cursor.Position;
            clickPos = Cursor.Position;

            if (MouseDown != null)
            {
                HookMouseEventArgs hm = new HookMouseEventArgs(e, Point.Empty, oldPos, clickPos);
                MouseDown(sender, hm);
                oldPos = hm.OldPosition;
            }
        }

        void MouseUpHandler(Object sender, MouseEventArgs e)
        {
            oldPos = new Point(0, 0);

            if (MouseUp != null)
            {
                HookMouseEventArgs hm = new HookMouseEventArgs(e, Point.Empty, oldPos, clickPos);
                MouseUp(sender, hm);
                oldPos = hm.OldPosition;
            }
        }

        void MouseMoveHandler(Object sender, MouseEventArgs e)
        {
            HookMouseEventArgs ne = new HookMouseEventArgs(e, Point.Empty, Point.Empty, clickPos);
            ne.MoveDelta = new Point(Cursor.Position.X - oldPos.X, Cursor.Position.Y - oldPos.Y);
            oldPos = Cursor.Position;
            ne.OldPosition = oldPos;

            if (MouseMove != null)
            {
                MouseMove(sender, ne);
                oldPos = ne.OldPosition;
            }
        }
    }
}